博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SVG 在 image 标签中的动态修改技巧
阅读量:6274 次
发布时间:2019-06-22

本文共 2076 字,大约阅读时间需要 6 分钟。

tag: Web; JavaScript; SVG; DOM; 动画 SVG

最近在项目中遇到了「带动画 SVG 图标」与 「image」标签结合使用的场景,使用过程中发现水还是有点深,因此整理出来,供有相似场景的童鞋以参考。

问题背景

我们这里有一个的带动画

这是一个水波纹效果的 SVG,动画时长是固定的,但是我们希望不同的标记动画的播放时长可以略有不同,进而产生错落交错的感觉。期待效果如下:

其中控制动画时长的属性是写死在 SVG 文件中的(animate 标签的 dur 属性)。SVG 部分内容如下:

复制代码

另外受限于组件要求,仅能使用 image标签进行加载 SVG。因此只能从 image.src 属性作为突破入口。

解题思路

先确定基本思路:在 SVG 被插入到 image 标签前,修改 SVG 文件中动画 animate 标签的属性 dur,以达到修改动画时间的目的。

那么我们先来看下 image 加载 SVG 文件几种的方式。

1. image 的 src 直接指定文件路径

复制代码

这种方式加载出来的 SVG 内容没法被 JS 获取到,更不要提修改属性,因此该方案 放弃

2. 直接加载 base64 或者 Blob URL 字符串

这种方式中,依靠的是 image 标签支持 base64 和 Blob 类型 URL 的特性。

考虑可以先将 SVG 文件转换为对应的字符串,然后通过正则表达式将动画属性修改,然后传入 src 中来实现。不过这种方式需要编写复杂的正则表达式,并且字符串形式的 SVG 内容可读性较差,因此这种方式也 不是最优的

如果可以先以 dom 形式修改 SVG 的动画属性,再将 dom 转换为字符串,最后再将字符串转换为 base64 或者 Blob 类型,就可以实现以上的需求了。

看起来这个思路靠谱,那么就按照这个方向继续探索。

处理过程

1. 获取 dom

获取 SVG 的方式有很多,但获取方式不在本文重点,故只给出原生 JS 实现方式。

const xhr = new XMLHttpRequest();xhr.addEventListener('load', () => {  const resXML = xhr.responseXML;  const svgDom = resXML.documentElement.cloneNode(true);});xhr.open('GET', './rings.svg');xhr.send();复制代码

2. 修改 dom

上文获取的 svgDom 就是可操作的 dom 节点,接下来和操作 dom 一样来操作它。

// 获取 svg 中的 animate 标签,使用 setAttribute 进行修改 dur、begin 等属性,以下代码仅为示例// 获取 animation 节点const ani = svgDom.children[0];// 修改节点上的动画时长 dur 属性ani.setAttribute('dur', Math.random() + 2 + 's');复制代码

3. 转换 domString

接来下便需要将 dom 转换成字符串:通过 XMLSerializer 将 XML 转换成 String 类型。

const svgStr = new XMLSerializer().serializeToString(svgDom);复制代码

4. 转换 URL

但是上面的 svgStr 是没法直接传给 image.src 的,需要将其转换为 image 可以解析的 base64 或者 Blob URL 类型。

方案 A:

这里我选择了 Blob 类型进行转换,先用 new Blob([svgStr]) 转换成 Blob 类型,再通过 URL.createObjectURL(blob) 方法将字符串转换成 Blob 类型 URL 传入。

const blob = new Blob([svgStr], {    type: 'image/svg+xml'});const blobStr = URL.createObjectURL(blob);const template = ``;// 最后插入模板复制代码
方案 B:

当然除了使用 Blob 数据类型外,我们也可以使用window.btoa()方法将 svgStr 转换为 base64 类型传入。

const base64 = window.btoa(svgStr);const template = ``// 最后插入模板复制代码

结论

通过「读入 SVG -> 修改属性 -> 转换 URL -> 传入 image」 这样一个流程,最终实现了我们的预期。

以上思路希望对有类似场景的同学们有所启发。 最后强调的是使用环境为 Chrome 浏览器,其他浏览器未做测试。

参考资料

转载地址:http://kxwva.baihongyu.com/

你可能感兴趣的文章
swoole异步任务task处理慢请求简单实例
查看>>
DHCP
查看>>
oracle数据泵导入分区表统计信息报错(四)
查看>>
spring技术内幕读书笔记之IoC容器的学习
查看>>
细说多线程(五) —— CLR线程池的I/O线程
查看>>
JavaScript instanceof和typeof的区别
查看>>
Hadoop文件系统详解-----(一)
查看>>
《面向模式的软件体系结构2-用于并发和网络化对象模式》读书笔记(8)--- 主动器...
查看>>
状态码
查看>>
我的友情链接
查看>>
用sqlplus远程连接oracle命令
查看>>
多年一直想完善的自由行政审批流程组件【2002年PHP,2008年.NET,2010年完善数据设计、代码实现】...
查看>>
自动生成四则运算题目
查看>>
【翻译】使用新的Sencha Cmd 4命令app watch
查看>>
【前台】【单页跳转】整个项目实现单页面跳转,抛弃iframe
查看>>
因为你是前端程序员!
查看>>
数据库设计中的14个技巧
查看>>
Android学习系列(5)--App布局初探之简单模型
查看>>
git回退到某个历史版本
查看>>
ecshop
查看>>